<template>
  <div class="container">
    <span>点击事件：点击平台触发放缩</span>
    <button @click="canRotation = !canRotation">旋转</button>
    <button @click="canMove = !canMove">平移</button>
    <button @click="textureChange">纹理替换</button>

    <!-- 场景容器 -->
    <div ref="canvasContainer" class="canvas-wrapper"></div>

    <!-- 加载状态 -->
    <div v-if="loading" class="loading-overlay">
      <div class="progress-bar">
        <div class="progress" :style="{ width: progress + '%' }"></div>
        <span>{{ Math.floor(progress) }}%</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, shallowRef } from "vue";
import * as THREE from "three";
import { OBJLoader } from "three/addons/loaders/OBJLoader.js";
import { MTLLoader } from "three/addons/loaders/MTLLoader.js";

// 【点击模型事件】
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
const onMouseClick = (event) => {
  // 将鼠标点击位置从屏幕坐标转换为归一化设备坐标（NDC）
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  // 更新射线投射器的射线位置
  raycaster.setFromCamera(mouse, camera.value);

  // 计算射线与模型的交点
  const intersects = raycaster.intersectObjects(scene.value.children, true); // true 表示递归检查子对象
  if (intersects.length > 0 && !intersects[0].object.name) {
    console.log("Intersected object:", intersects[0].object); // 处理交点对象
    const newScale = intersects[0].object.parent.scale.x > 1 ? 1 : 1.1;
    intersects[0].object.parent.scale.x = newScale;
    intersects[0].object.parent.scale.y = newScale;
    intersects[0].object.parent.scale.z = newScale;
  }
};

window.addEventListener("click", onMouseClick, false);

// 拖转控制器
import { DragControls } from "three/addons/controls/DragControls.js";
let dragControls;
// 交互控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { Vector3 } from "three";
let controls = null;
const initControls = () => {
  // 初始化交互控制器
  const controls = new OrbitControls(camera.value, renderer.value.domElement);
  controls.enableDamping = true; // 启用阻尼效果‌
  controls.dampingFactor = 0.05; // 阻尼系数
  controls.rotateSpeed = 0.8; // 旋转灵敏度
  controls.zoomSpeed = 0.8; // 缩放灵敏度
  controls.panSpeed = 0.8; // 平移灵敏度

  // 初始化拖拽
  dragControls = new DragControls(
    models,
    camera.value,
    renderer.value.domElement
  );
  dragControls.addEventListener("dragstart", (event) => {
    canMove = false;
    canRotation = false;
    controls.enablePan = false;
    controls.enableZoom = false;
    controls.enableRotate = false;
    controls.enableDamping = false;
    let curModel = event.object.parent;
    curModel.rotation.set(0, 0, 0);
    event.object.getWorldPosition(worldPos);
    console.log("dragstart", event.object.position, worldPos);
  });

  dragControls.addEventListener("drag", (event) => {
    boxCheck(event);
  });

  dragControls.addEventListener("dragend", (event) => {
    controls.enablePan = true;
    controls.enableZoom = true;
    controls.enableRotate = true;
    boxCheck(event);
  });

  loading.value = false;
  return controls;
};

//碰撞重置
const boxCheck = (event) => {
  // 实时更新包围盒
  boxs.forEach((box, index) => {
    boxs[index].setFromObject(models[index]);
  });
  let curModel = event.object.parent;

  curModel.scale.set(1, 1, 1);

  curModel.getWorldPosition(worldPos);

  // 模型间检测碰撞
  if (boxs[0].intersectsBox(boxs[1])) {
    event.object.position.copy(lastPosition);
    console.log("碰撞", lastPosition);
    return;
  }

  lastPosition.x = event.object.position.x;
  lastPosition.y = event.object.position.y;
  lastPosition.z = event.object.position.z;

  // 平台和模型检测
  if (
    boxs[0].intersectsBox(platformBBox) ||
    boxs[1].intersectsBox(platformBBox) ||
    (event.object.position.x > -2.5 &&
      event.object.position.x < 2.5 &&
      event.object.position.z > -2.5 &&
      event.object.position.z < 2.5 &&
      event.object.position.y < 0.2)
  ) {
    console.log("平台和模型检测", lastPosition);
    lastPosition.x = event.object.position.x;
    lastPosition.y = event.object.position.y;
    lastPosition.y = -0.4;
    event.object.position.copy(lastPosition);
  } else {
    event.object.position.copy(lastPosition);
  }
};

// 配置参数
let models = null;
let boxs = [];
let lastPosition = new THREE.Vector3();
let modelX = 0.01;
let countMoveX = 0;
let canRotation = false;
let canMove = false;
const modelConfigs = [
  {
    name: "tasse1",
    obj: "src/assets/models/tasse.obj",
    mtl: "src/assets/models/tasse.mtl",
    position: { x: 2, y: 0, z: 0 },
    scale: 1,
  },
  {
    name: "tasse2",
    obj: "src/assets/models/tasse.obj",
    mtl: "src/assets/models/tasse.mtl",
    position: { x: -3, y: 0, z: 0 },
    scale: 1,
  },
];
// 纹理导入
const textureLoader = new THREE.TextureLoader();
const newMaterial = new THREE.MeshPhongMaterial({
  map: textureLoader.load("src/assets/pictures/pic.jpeg"), // 漫反射贴图‌:ml-citation{ref="8" data="citationList"}
  normalMap: textureLoader.load("src/assets/pictures/pic.jpeg"), // 法线贴图‌:ml-citation{ref="5" data="citationList"}
});
const textureChange = () => {
  scene.value.traverse((child) => {
    if (child.isMesh) {
      // 保留原始几何数据
      const geometry = child.geometry;
      // 应用新材质‌:ml-citation{ref="1,5" data="citationList"}
      child.material = newMaterial;
      // 计算UV坐标‌:ml-citation{ref="3" data="citationList"}
      geometry.computeVertexNormals();
      geometry.attributes.uv.needsUpdate = true;
    }
  });
};

// 响应式状态
const canvasContainer = ref(null);
const loading = ref(true);
const progress = ref(0);
const scene = shallowRef(new THREE.Scene());
const camera = shallowRef(null);
const renderer = shallowRef(null);

// 初始化基础场景
const initScene = () => {
  // 创建渲染器
  renderer.value = new THREE.WebGLRenderer({ antialias: true });
  renderer.value.setSize(window.innerWidth, window.innerHeight);
  renderer.value.setPixelRatio(window.devicePixelRatio);
  renderer.value.shadowMap.enabled = true;
  renderer.value.shadowMap.type = THREE.PCFSoftShadowMap;
  canvasContainer.value.appendChild(renderer.value.domElement);

  // 设置相机
  camera.value = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  camera.value.position.set(5, 5, 5);
  camera.value.lookAt(0, 0, 0);
};

// 加载材质
const loadMaterial = async (mtlPath) => {
  return new Promise((resolve) => {
    new MTLLoader().load(mtlPath, (materials) => {
      materials.preload();
      resolve(materials);
    });
  });
};

// 加载单个模型
const loadModel = async (config) => {
  try {
    // 加载材质
    let materials = null;
    if (config.mtl) {
      materials = await loadMaterial(config.mtl);
    }

    // 加载OBJ模型
    const loader = new OBJLoader();
    // console.log({ materials });
    if (materials) loader.setMaterials(materials);

    return new Promise((resolve, reject) => {
      loader.load(
        config.obj,
        (obj) => {
          // 设置模型属性
          obj.position.set(
            config.position.x,
            config.position.y,
            config.position.z
          );
          obj.scale.set(config.scale, config.scale, config.scale);
          obj.name = config.name;

          resolve(obj);
        },
        (xhr) => {
          progress.value = (xhr.loaded / xhr.total) * 100;
        },
        (error) => reject(error)
      );
    });
  } catch (error) {
    console.error(`模型加载失败: ${config.obj}`, error);
    return null;
  }
};

// 设置添加光照
const setupLighting = () => {
  // 环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.value.add(ambientLight);

  // 方向光
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  directionalLight.position.set(5, 5, 3);
  directionalLight.castShadow = true;
  directionalLight.shadow.mapSize.width = 2048;
  directionalLight.shadow.mapSize.height = 2048;
  scene.value.add(directionalLight);
};

// 动画循环
const animate = () => {
  requestAnimationFrame(animate);
  models.forEach((model) => {
    // checkSnap(model);
    // console.log({ model });
    if (model) {
      //旋转
      if (canRotation) {
        // model.rotation.x += 0.01;
        model.rotation.y += 0.01;
        // model.rotation.z += 0.01;
      }

      // 平移
      if (canMove) model.position.x += modelX;
    }
  });
  if (canMove) {
    countMoveX += modelX;
    if (countMoveX >= 1 || countMoveX <= 0) {
      modelX *= -1;
    }
  }

  // controls.update()
  renderer.value.render(scene.value, camera.value);
};

// 初始化平台
let worldPos = new THREE.Vector3();

let platformBBox, snapZone, platformP;
const initPlatform = () => {
  platformP = new THREE.Mesh(
    new THREE.BoxGeometry(5, 0.3, 5),
    new THREE.MeshPhongMaterial({ color: 0x808080 })
  );
  platformP.position.set(0, 0, 0);
  scene.value.add(platformP);

  platformBBox = new THREE.Box3().setFromObject(platformP);
  // snapZone = platformBBox.expandByScalar(0.3);
};

// 初始化加载
const initialize = async () => {
  initScene();
  initPlatform();
  setupLighting();

  // 并行加载所有模型
  models = await Promise.all(modelConfigs.map(loadModel));

  // 添加模型到场景
  models.forEach((model) => {
    // console.log({ model });
    if (model) {
      scene.value.add(model);
      //
      const box = new THREE.Box3().setFromObject(model);
      boxs.push(box);
    }
  });

  initControls();
  animate();
};

//

// 窗口适配
const onWindowResize = () => {
  camera.value.aspect = window.innerWidth / window.innerHeight;
  camera.value.updateProjectionMatrix();
  renderer.value.setSize(window.innerWidth, window.innerHeight);
};

// 生命周期
onMounted(() => {
  initialize();
  window.addEventListener("resize", onWindowResize);
});

onUnmounted(() => {
  window.removeEventListener("resize", onWindowResize);
  scene.value.traverse((child) => {
    if (child.isMesh) {
      child.geometry.dispose();
      if (child.material.map) child.material.map.dispose();
      child.material.dispose();
    }
  });
  renderer.value.dispose();
});
</script>

<style scoped>
.container {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.canvas-wrapper {
  width: 100%;
  height: 100%;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
}

.progress-bar {
  width: 300px;
  height: 20px;
  background: #333;
  border-radius: 10px;
  overflow: hidden;
  position: relative;
}

.progress {
  height: 100%;
  background: #00ff88;
  transition: width 0.3s ease;
}

.progress-bar span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  color: white;
  font-family: Arial;
  font-size: 12px;
}
button{
  margin-left: 5px;
  border-color: #333;
}
span{
  color: #5f0404;
}
</style>
